package com.aleyn.processor.scanner

import com.aleyn.annotation.Autowired
import com.aleyn.annotation.Route
import com.aleyn.processor.data.RouterMeta
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSPropertyDeclaration

/**
 * @author : Aleyn
 * @date : 2023/07/25 : 21:35
 *
 * 为 `KSClassDeclaration` 提供扩展函数，用于在 KSP 编译期从符号中提取 LRouter 框架所需的元数据。
 * 这些函数是连接注解处理器与代码生成的桥梁，负责将注解信息转换为结构化的元数据对象。
 */

/**
 * 从一个类声明中创建 `RouterMeta.RouterAutowired` 元数据。
 *
 * 此函数的核心职责是扫描一个给定的类 (`KSClassDeclaration`)，查找所有被 `@Autowired` 注解标记的属性。
 * 对于每一个找到的属性，它会提取注解中指定的 `key`（如果未指定，则为空字符串）以及属性本身的信息 (`KSPropertyDeclaration`)。
 * 最终，这些信息被封装到一个 `RouterMeta.RouterAutowired` 对象中，该对象将在代码生成阶段用于创建依赖注入的逻辑。
 *
 * @receiver [KSClassDeclaration] 要进行扫描的 KSP 类声明。
 * @return 如果在类中找到了至少一个被 `@Autowired` 注解标记的属性，则返回一个包含所有自动注入信息的 `RouterMeta.RouterAutowired` 实例；
 *         如果在类中没有找到任何 `@Autowired` 属性，则返回 `null`。
 */
fun KSClassDeclaration.createAutowiredClass(): RouterMeta.RouterAutowired? {
    val list = arrayListOf<Pair<String, KSPropertyDeclaration>>()
    val pkgName = this.packageName.asString()
    val className = this.simpleName.asString()

    this.declarations
        .filterIsInstance<KSPropertyDeclaration>() // 仅处理属性声明
        .forEach { property ->
            // 查找属性上的 @Autowired 注解
            property.annotations.firstOrNull {
                it.shortName.asString() == Autowired::class.simpleName
            }?.let { ann ->
                // 获取注解中定义的 key，如果用户未指定，则默认为空字符串
                val paramKey = ann.arguments.firstOrNull()?.value.toString()
                list.add(paramKey to property)
            }
        }
    // 只有当至少存在一个 @Autowired 属性时，才创建元数据对象
    if (list.isNotEmpty()) {
        return RouterMeta.RouterAutowired(pkgName, className, list)
    }
    return null
}

/**
 * 从一个类声明中创建 `RouterMeta.ModuleRouter` 元数据。
 *
 * 此函数用于处理被 `@Route` 注解标记的类，将其转换为代表一个路由节点的 `RouterMeta.ModuleRouter` 元数据。
 * 它会检查类声明上的所有注解，如果找到了 `@Route` 注解，就会提取其参数，
 * 包括 `path` (路由路径), `desc` (路由描述), 和 `other` (其他自定义标志)。
 * 这些信息连同类的完全限定名一起，被用来构建一个 `RouterMeta.ModuleRouter` 对象，供后续的路由表生成逻辑使用。
 *
 * @receiver [KSClassDeclaration] 要进行扫描的 KSP 类声明。
 * @return 如果该类被 `@Route` 注解标记，则返回一个填充了路由信息的 `RouterMeta.ModuleRouter` 实例；
 *         如果未找到 `@Route` 注解，则返回 `null`。
 */
fun KSClassDeclaration.createModuleRouter(): RouterMeta.ModuleRouter? {

    this.annotations.forEach { annotation ->
        if (annotation.shortName.asString() == Route::class.simpleName) {
            val router = RouterMeta.ModuleRouter()
            router.className = this.qualifiedName?.asString().orEmpty()
            // 遍历注解的所有参数，并根据参数名称将其值赋给元数据对象的相应字段
            annotation.arguments.forEach {
                when (it.name?.asString()) {
                    Route::path.name -> router.path = it.value.toString()
                    Route::desc.name -> router.desc = it.value.toString()
                    Route::other.name -> router.other = it.value as Int
                }
            }
            return router
        }
    }
    return null
}